import json
import pickle
import shutil
import yaml
import os
import zipfile
import tarfile

class FileTool:
    """
    读/写 json文件
    读/写 yaml文件
    删除/创建 目录
    删除/复制 文件
    压缩/解压 文件
    移动 目录/文件
    """

    @classmethod
    def read_json(cls, file, default=None):
        if default is None:
            default = {}
        try:
            with open(file, "r", encoding="utf-8") as infile:
                return json.load(infile)
        except Exception as e:
            print("error reading json: {}, using {}".format(e, default))
            return default

    @classmethod
    def write_json(cls, data, to_file):
        with open(to_file, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=4, sort_keys=True)

    @classmethod
    def write_json_v2(cls, data, to_file):
        with open(to_file, "w", encoding="utf-8") as f:
            json.dump(data, f, indent=4, sort_keys=True, ensure_ascii=False)

    @classmethod
    def delete_directory(cls, directory, verbose=False):
        if os.path.isdir(directory):
            shutil.rmtree(directory)
            if verbose:
                print(f"removed directory: {directory}")

    @classmethod
    def make_directory(cls, directory, delete=False, exist_ok=True):
        if delete:
            cls.delete_directory(directory)
        if not os.path.isdir(directory):
            os.makedirs(directory, exist_ok=exist_ok)
        return os.path.abspath(directory)

    @classmethod
    def delete_file(cls, file, verbose=False):
        if os.path.isfile(file):
            try:
                os.remove(file)
            except Exception as e:
                print(e)

            if verbose:
                print(f"removed file: {file}")

    @classmethod
    def copy_file(cls, from_file, to_file, exist_ok=True):
        if os.path.isfile(from_file):
            if not os.path.isdir(os.path.dirname(to_file)):
                os.makedirs(os.path.dirname(to_file), exist_ok=exist_ok)
            shutil.copyfile(from_file, to_file)

    @classmethod
    def move_folder(cls, from_folder, to_folder, exist_ok=True):
        if os.path.isdir(from_folder):
            if not os.path.isdir(os.path.dirname(to_folder)):
                os.makedirs(os.path.dirname(to_folder), exist_ok=exist_ok)
            shutil.move(from_folder, to_folder)

    @classmethod
    def move_files(cls, fromFolder, toFolder):
        new_paths = []
        for f in os.listdir(fromFolder):
            file_path = os.path.join(toFolder, f)
            shutil.move(os.path.join(fromFolder, f), file_path)
            new_paths.append(file_path)
        return new_paths

    @classmethod
    def files_in_folder(cls, folder):
        return [os.path.join(folder, n) for n in os.listdir(folder) if os.path.isfile(os.path.join(folder, n))]

    @classmethod
    def folders_in_folder(cls, folder):
        return [os.path.join(folder, n) for n in os.listdir(folder) if os.path.isdir(os.path.join(folder, n))]

    @classmethod
    def unzip_file(cls, file, dest):
        file_zip = zipfile.ZipFile(file)
        file_zip.extractall(dest)
        file_zip.close()
        return dest

    @classmethod
    def zip_folder(cls, folder, dest):
        zipf = zipfile.ZipFile(dest, "w", zipfile.ZIP_DEFLATED)
        for root, dirs, files in os.walk(folder):
            for file in files:
                zipf.write(
                    os.path.join(root, file),
                    os.path.join(os.path.relpath(root, folder), file),
                )
        zipf.close()
        return dest

    @classmethod
    def read_file(cls, filepath, mode="r"):
        f = open(filepath, mode)
        content = f.read()
        f.close()
        return content

    @classmethod
    def write_file(cls, b64_str, save_path, mode='w'):
        try:
            with open(save_path, mode) as f:
                f.write(b64_str)
            return True
        except Exception as e:
            print(e)
            return False

    @classmethod
    def read_yaml(cls, file, default=None, err_msg=None):
        if default is None:
            default = {}
        try:
            with open(file, "r") as f:
                return yaml.load(f, Loader=yaml.FullLoader)
        except Exception as e:
            if err_msg is not None:
                print(err_msg)
            else:
                print("error reading yaml: {}, using {}".format(e, default))
            return default

    @classmethod
    def write_yaml(cls, data, file, **kwds):
        with open(file, "w") as outfile:
            yaml.dump(data, outfile, **kwds)

    @classmethod
    def write_pkl(cls, filepath, data):
        with open(filepath, "wb") as f:
            pickle.dump(data, f)

    @classmethod
    def read_pkl(cls, filepath):
        with open(filepath, "rb") as f:
            return pickle.load(f)

    @classmethod
    def read_png(cls, file_path):
        img = Image.open(file_path)
        img_arr = np.array(img)
        return img_arr
    
    @classmethod
    def tar_gz(cls, fname):
        t = tarfile.open(fname + ".tar.gz", "w:gz") 
        for root, directory, files in os.walk(fname): 
            print(root, directory, files )
            for file in files: 
                fullpath = os.path.join(root, file) 
            t.add(fullpath) 
        t.close() 

    @classmethod
    def tar(cls, fname):
        t = tarfile.open(fname + ".tar", "w") 
        for root, directory, files in os.walk(fname): 
            print(root, directory, files )
            for file in files: 
                fullpath = os.path.join(root, file) 
            t.add(fullpath) 
        t.close() 

    @classmethod
    def untar(cls,fname,dirs):
        t = tarfile.open(fname) 
        t.extractall(path = dirs)